﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Extensions.Location;
using Google.GData.Photos;
using PowerWaveAddin.Properties;
using PowerWaveAddin.UserControls;
using System.Threading;

namespace PowerWaveAddin.Uploaders
{
	internal class PicasaUploader : AbstractUploader
	{
		#region Fields

		private PicasaService m_PicasaService;
		private Dictionary<string, Uri> m_PictureUriMap;
		private PicasaConfigControl m_PicasaConfigControl;

		#endregion

		#region Properties

		public override UploadConfigControl GuiControl
		{
			get
			{
				if (m_PicasaConfigControl == null)
					m_PicasaConfigControl = new PicasaConfigControl();
				return m_PicasaConfigControl;
			}
		}

		public override string FriendlyName
		{
			get { return "Picasa"; }
		}

		#endregion

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="Username">Username of the Picasa Web Albums user</param>
		/// <param name="Password">Password of the user</param>
		public PicasaUploader()
		{
			UploadConfigData.Instance.UploadConfigDataChanged += new UploadConfigData.UploadConfigDataChangedHandler(OnUploadConfigDataChanged);
			m_PicasaService = new PicasaService(Resources.Picasa_ApplicationName);
			try { m_PicasaService.setUserCredentials(UploadConfigData.Instance.Picasa_Username, UploadConfigData.Instance.Picasa_Password); }
			catch (Exception) { }
			m_PictureUriMap = new Dictionary<string, Uri>();
		}

		/// <summary>
		/// Updates the picasa service when the config data is changed
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnUploadConfigDataChanged(object sender, EventArgs e)
		{
			m_PicasaService.setUserCredentials(UploadConfigData.Instance.Picasa_Username, UploadConfigData.Instance.Picasa_UnsavedPassword);
		}

		/// <summary>
		/// Uploads the given list of pictures to Picasa Web Albums putting them into the given album (which must be public).
		/// If the album doesn't exist it is created.
		/// </summary>
		/// <param name="AlbumName">Name of a public album</param>
		/// <param name="Pictures">List of pictures to upload (full qualified file paths)</param>
		public override void Upload(string AlbumName, IEnumerable<string> Pictures)
		{
			int count = 0;
			int retryMax = 3;

			AlbumAccessor album = EnsureAlbumExists(AlbumName);
			Uri postUri = new Uri(PicasaQuery.CreatePicasaUri(m_PicasaService.Credentials.Username, album.Id));

			foreach (string pictureFile in Pictures)
			{
				for (int retryCount = 0; retryCount <= retryMax; retryCount++)
				{
					if (retryCount == retryMax)
						throw new IOException("After several retries, the picture has not uploaded. Better luck next time");
					try
					{
						using (FileStream pictureStream = File.OpenRead(pictureFile))
						{
							PicasaEntry newPhotoEntry = (PicasaEntry)m_PicasaService.Insert(postUri, pictureStream,
								String.Format("image/{0}", Path.GetExtension(pictureFile).TrimStart('.')), pictureFile);
							m_PictureUriMap.Add(pictureFile, new Uri(newPhotoEntry.Media.Content.Attributes["url"].ToString()));
							RaiseUploadProgress(new UploadProgressArgs()
							{
								LastSlideUploadedIndex = count++,
								LastSlideUploadedPath = pictureFile,
								LastSlideUploadedUri = new Uri(newPhotoEntry.Media.Content.Attributes["url"].ToString()),
								TotalSlides = Pictures.Count()
							});
						}
						break;
					}
					catch (IOException ex_p)
					{
						Thread.Sleep(2000);
					}
				}
			}
		}

		/// <summary>
		/// Returns the final mapping of all things uploaded through this uploader
		/// </summary>
		/// <returns></returns>
		public override Dictionary<string, Uri> GetFileUriMapping()
		{
			return m_PictureUriMap;
		}

		public override string ToString()
		{
			return FriendlyName;
		}

		/// <summary>
		/// Gets or creates the given public album
		/// </summary>
		/// <param name="AlbumName">Name of the public album to get or create</param>
		/// <returns>AlbumAccessor referencing the desired album</returns>
		private AlbumAccessor EnsureAlbumExists(string AlbumName)
		{
			AlbumQuery albumQuery = new AlbumQuery(PhotoQuery.CreatePicasaUri(m_PicasaService.Credentials.Username));
			PicasaFeed albumFeed = m_PicasaService.Query(albumQuery);
			foreach (PicasaEntry albumEntry in albumFeed.Entries)
			{
				AlbumAccessor album = new AlbumAccessor(albumEntry);
				if (album.AlbumTitle == AlbumName)
					return album;
			}

			// Album doesn't exist, create it
			AlbumEntry newAlbum = new AlbumEntry();
			newAlbum.Title.Text = AlbumName;
			AlbumAccessor ac = new AlbumAccessor(newAlbum);
			ac.Access = "public";

			Uri feedUri = new Uri(PicasaQuery.CreatePicasaUri(m_PicasaService.Credentials.Username));

			return new AlbumAccessor(m_PicasaService.Insert(feedUri, newAlbum));
		}
	}
}
